/*
 * Copyright (C) 2013 gujicheng
 * 
 * Licensed under the GPL License Version 2.0;
 * you may not use this file except in compliance with the License.
 * 
 * If you have any question, please contact me.
 * 
 *************************************************************************
 **                   Author information                                **
 *************************************************************************
 ** Email: gujicheng197@126.com                                         **
 ** QQ   : 29600731                                                     **
 ** Weibo: http://weibo.com/gujicheng197                                **
 *************************************************************************
 */
package com.libra.sinvoice

import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue

/**
 *
 * @ClassName: com.libra.sinvoice.Buffer
 * @Description: 缓冲器
 * @author zhaokaiqiang
 * @date 2014-11-15 下午1:35:46
 */
class Buffer @JvmOverloads constructor(// 缓冲区数量
        private val mBufferCount: Int = Common.DEFAULT_BUFFER_COUNT, // 缓冲区体积
        private val mBufferSize: Int = Common.DEFAULT_BUFFER_SIZE) {
    // 生产者队列
    private val mProducerQueue: BlockingQueue<BufferData>
    // 消费者队列
    private val mConsumeQueue: BlockingQueue<BufferData>

    val emptyCount: Int
        get() = mProducerQueue.size

    val fullCount: Int
        get() = mConsumeQueue.size

    // 获取生产者的头结点，阻塞式
    val empty: BufferData?
        get() = getImpl(mProducerQueue)

    // 获取消费者的头结点
    val full: BufferData?
        get() = getImpl(mConsumeQueue)

    init {
        mProducerQueue = LinkedBlockingQueue(mBufferCount)
        // we want to put the end buffer, so need to add 1
        mConsumeQueue = LinkedBlockingQueue(mBufferCount + 1)

        // 初始化生产者队列
        for (i in 0 until mBufferCount) {
            try {
                mProducerQueue.put(BufferData(mBufferSize))
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }

        }
    }

    fun reset() {
        // 将生产者的空头结点剔除
        var size = mProducerQueue.size
        for (i in 0 until size) {
            val data = mProducerQueue.peek()
            if (null == data || null == data.byteData) {
                mProducerQueue.poll()
            }
        }

        // 将消费者中的非空数据添加到生产者当中
        size = mConsumeQueue.size
        for (i in 0 until size) {
            val data = mConsumeQueue.poll()
            if (null != data && null != data.byteData) {
                mProducerQueue.add(data)
            }
        }

        LogHelper.d(TAG, "reset ProducerQueue Size:" + mProducerQueue.size
                + "    ConsumeQueue Size:" + mConsumeQueue.size)
    }

    // 加入到生产者中
    fun putEmpty(data: BufferData): Boolean {
        return putImpl(data, mProducerQueue)
    }

    // 加入到消费者中
    fun putFull(data: BufferData): Boolean {
        return putImpl(data, mConsumeQueue)
    }

    // 获取队列的头结点
    private fun getImpl(queue: BlockingQueue<BufferData>?): BufferData? {
        if (null != queue) {
            try {
                return queue.take()
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }

        }
        return null
    }

    // 将数据加入到队列中
    private fun putImpl(data: BufferData?, queue: BlockingQueue<BufferData>?): Boolean {
        if (null != queue && null != data) {
            try {
                queue.put(data)
                return true
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }

        }
        return false
    }

    // when mData is null, means it is end of input
    class BufferData(// 缓冲最大体积
            val maxBufferSize: Int) {
        // 数据容器
        var byteData: ByteArray? = null
        // 填充体积
        // 设置填充数量
        var filledSize: Int = 0

        init {
            filledSize = 0

            if (maxBufferSize > 0) {
                byteData = ByteArray(this.maxBufferSize)
            } else {
                byteData = null
            }
        }

        // 重置填充数量
        fun reset() {
            filledSize = 0
        }

        companion object {
            // 静态空缓冲区
            /**
             * 获取空的缓冲区
             *
             * @return
             */
            val emptyBuffer = BufferData(0)
        }
    }

    companion object {

        private val TAG = "Buffer"
    }

}
